package ga.main;

import ga.support.Chromosome;
import ga.support.GA;

import java.util.ArrayList;
import java.util.Date;
import java.util.Random;

import util.Reader;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
/**
 * 
 * @author abuzaher
 */
public class GALongestPath {

	private Random random;
	private GA ga;
	private int numIterations = 100;
	private int populationSize = 100;
	private double eliteFraction = 0.05;

	public GALongestPath(ArrayList<ArrayList<Double>> adjacencyMatrix) {
		random = new Random(new Date().getTime());
		ga = new GA(adjacencyMatrix, random);
		ga.setPopulationSize(populationSize);
		ga.setEliteFraction(eliteFraction);
	}

	public static void main(String args[]) {

		ArrayList<Double> data = readInputFromFile();

		ArrayList<ArrayList<Double>> adjacencyMatrix = createAdjacencyMatrixFromInputData(data);

		for (int j = 10; j < 200; j++) {
			int runs = 100;
			double optimumFitness = 1556.0;
			int successCount = 0;
			long totalExecTimeForAllRuns = 0;
			double quality = 0;

			for (int i = 0; i < runs; i++) {
				long startTime = System.nanoTime();

				GALongestPath gALongestPath = new GALongestPath(adjacencyMatrix);
				gALongestPath.setNumIterations(j);
				gALongestPath.runMainAlgo();

				long endTime = System.nanoTime();

				Chromosome chromosome = gALongestPath.ga.getBestChromosome();
				if (chromosome.getFitnesss() >= optimumFitness) {
					successCount++;
				}
				quality += chromosome.getFitnesss() / optimumFitness;

				totalExecTimeForAllRuns += endTime - startTime;

				// System.out.println("GLOBAL SOLUTION: " +
				// gALongestPath.ga.getBestChromosome());
			}

			// System.out.println(successCount / (double) runs * 100 +
			// "% success rate");
			// System.out.println("Avg Running time: " + totalExecTimeForAllRuns
			// / (double) runs / 1000000 + " milliseconds");
			// System.out.println("Avg quality: " + quality / runs * 100);
			System.out.println(j + " " + successCount / (double) runs * 100
					+ " " + totalExecTimeForAllRuns / (double) runs / 1000000
					+ " " + quality / runs * 100);
		}

	}

	private static ArrayList<ArrayList<Double>> createAdjacencyMatrixFromInputData(
			ArrayList<Double> data) {
		ArrayList<ArrayList<Double>> adjacencyMatrix = new ArrayList<ArrayList<Double>>();
		int size = (int) Math.sqrt(data.size());
		for (int i = 0; i < size; i++) {
			adjacencyMatrix.add(new ArrayList<Double>());
		}
		for (int i = 0; i < size; i++) {
			for (int j = 0; j < size; j++) {
				adjacencyMatrix.get(i).add(data.get(i * size + j));
			}
		}
		return adjacencyMatrix;
	}

	private static ArrayList<Double> readInputFromFile() {
		// Reader.openFile("input2.txt");
		// Reader.openFile("input3.txt");
		// Reader.openFile("input4 .txt");
		// Reader.openFile("input5.txt");
		Reader.openFile("input/input6.txt");
		ArrayList<Double> data = Reader.readFile();
		Reader.closeFile();
		return data;
	}

	@SuppressWarnings("unused")
	public void runMainAlgo() {
		ga.generateInitialPopulation();

		// Validator validator = new Validator(ga);
		// validator.validateCurrrentGeneration(ga.getChromosomes());

		double prevFitness = ga.getBestChromosomeFitness();
		// System.out.println(ga.getBestChromosome());

		for (int i = 0; i < numIterations; i++) {

			// corssover operation
			ga.applyCrossover();

			// code for mutation
			int perturbationFactor = ga.getPerturbationFactor();
			// System.out.println(perturbationFactor);

			ga.applyMutation();
			// validator.validateCurrrentGeneration();
			double newFitness = ga.getBestChromosomeFitness();

			// System.out.println(prevFitness);
			// System.out.println(newFitness);

			// if no improvement
			if (prevFitness == newFitness) {
				// perturbationFactor += 1;
				ga.increasePerturbationInNextIncrement = true;
				// if (perturbationFactor > (ga.getBestChromosome().getLength()
				// - 1) / 2) {
				// System.out.println("RESET");
				// perturbationFactor = ga.perturbationFactorInitialValue;
				// }
				// ga.setPurturbationFactor(perturbationFactor);

				// if (perturbationFactor < (1 - delta)) {
				// // increase the perturbation factor so that the mutation is
				// // applied to more in the center and more variation is
				// achieved
				// perturbationFactor += delta;
				// if (perturbationFactor > 1) {
				// System.out.println("RESET");
				// perturbationFactor = ga.perturbationFactorInitialValue;
				// }
				// ga.setPurturbationFactor(perturbationFactor);
				// }
			}

			prevFitness = newFitness;

			// System.out.println(ga.getBestChromosome());

		}
	}

	public void setNumIterations(int numIterations) {
		this.numIterations = numIterations;
	}

	public void setPopulationSize(int populationSize) {
		this.populationSize = populationSize;
	}

	public void setEliteFraction(double eliteFraction) {
		this.eliteFraction = eliteFraction;
	}
}
